package logic

import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	"github.com/we7coreteam/w7-rangine-go/src/core/err_handler"
	"log"
	"net/http"
	"time"
)

func NewClientConn(ctx *gin.Context) (*Client, error) {
	ws := websocket.Upgrader{
		CheckOrigin: func(r *http.Request) bool {
			return true
		},
		Error: func(w http.ResponseWriter, r *http.Request, status int, reason error) {},
	}
	wsConn, err := ws.Upgrade(ctx.Writer, ctx.Request, nil)
	if err_handler.Found(err) {
		return nil, err
	}
	client := &Client{
		Id:         ctx.Request.Header.Get("Sec-WebSocket-Key"),
		conn:       wsConn,
		IsDelete:   false,
		DeleteTime: 0,
	}
	client.SendMessageQueue = make(chan string)
	return client, nil
}

type Client struct {
	Id               string               // ws 用户连接标识
	Fd               string               // 业务系统中用户唯一标识
	Token            string               // 用户 Token，由前端 get 值传递
	conn             *websocket.Conn      // 当前 ws 连接
	CancelFunc       func(client *Client) // 断开回调函数，通知 collect 删除连接
	SendMessageQueue chan string          // 发送消息队列
	PullMsgFunc      func(message string) // 将消息推送给 collect 用于推送到队列
	IsDelete         bool                 // 标记当前连接是否已经断开
	DeleteTime       int64                // 删除时间
	CtxCancelFunc    context.CancelFunc
	CtxContext       context.Context
}

type Message struct {
	Fd      string `json:"fd"`      // 发送消息id
	Content string `json:"content"` // 消息内容
	RecvAt  int64  `json:"recv_at"`
	Type    int    `json:"type"` // 消息类型
}

func (self *Client) ReadMessage() {
	for {
		select {
		case <-self.CtxContext.Done():
			return
		default:
			recvMsgType, recvMsg, err := self.conn.ReadMessage()
			if err_handler.Found(err) {
				log.Printf("读取消息错误: %s \n", err.Error())
				self.CancelFunc(self)
				return
			}
			message := &Message{
				Fd:      self.Fd,
				Content: string(recvMsg),
				Type:    recvMsgType,
				RecvAt:  time.Now().Unix(),
			}
			userContentMsg := ContentMessage{}
			json.Unmarshal(recvMsg, &userContentMsg)

			if userContentMsg.Type == MESSAGE_TYPE_FD_INFO {
				self.SendMessageQueue <- fmt.Sprintf("{\"type\":\"fd_info\",\"fd_info\":\"%s\"}", self.Id)
				continue
			}

			if userContentMsg.Type == MESSAGE_TYPE_PING {
				if self.IsDelete {
					self.SendMessageQueue <- "false"
				} else {
					self.SendMessageQueue <- "PONG"
				}
				continue
			}

			log.Printf("接收消息: %+v \n", message)
			jsonString, _ := json.Marshal(message)
			self.PullMsgFunc(string(jsonString))
		}
	}
}

func (self *Client) SendMessage() {
	for {
		select {
		case <-self.CtxContext.Done():
			return
		case message := <-self.SendMessageQueue:
			if string(message) != "PONG" && string(message) != "false" {
				log.Printf("发送消息: %+v \n", message)
			}
			self.conn.WriteMessage(websocket.TextMessage, []byte(message))
		}
	}
}

func (self *Client) Close() error {
	self.conn.CloseHandler()(websocket.ClosePolicyViolation, "close repeat login")
	self.conn.Close()
	self.CtxCancelFunc()
	return nil
}
